

#include "TFConfigurator.h"
#include "sqlite3.h"
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <iostream>
using namespace std;

/**
 * Read configuration form table $table$ of sqlite database $file$
 * And fill configurations to Map<string,string>;
 */
TFConfigurator::TFConfigurator(const char * file, const char* table, bool ro)
{
    modified=false;
    readonly=ro;
    configs.clear();

    if( file==NULL || table==NULL)
    {
        cerr<<"Bad configuration database ("<<file<<") or table ("<<table<<") names!"<<endl;
        exit(-1);
    }
    database=file;
    config_table=table;
    
    sqlite3* dbhandle;
    if(0!=sqlite3_open(database.c_str(),&dbhandle)){
        cerr<<"Fail to open config database :"<<database<<endl;
        exit(-2);
    }
    sqlite3_stmt *stmt;
    string sql("SELECT * FROM ");
    sql.append(config_table);
    if(SQLITE_OK!=
       sqlite3_prepare(dbhandle,sql.c_str(),sql.size(),&stmt,NULL)
        ){
        cerr<<"Fail to prepare sql statement to retrieve data!"<<endl;
        exit(-2);
    }
    while(SQLITE_ROW==sqlite3_step(stmt)){
        string k((const char*)sqlite3_column_text(stmt,0));
        string v((const char*)sqlite3_column_text(stmt,1));
        configs.insert(pair<string,string>(k,v));
    }
    if(SQLITE_ABORT==sqlite3_finalize(stmt)){
        cerr<<"Fail to close sql statement:"<<sql.c_str()<<endl;
        exit(-2);
    }
    sqlite3_close(dbhandle);
}

void TFConfigurator::WriteBack(){
        //If modified,then write back!
    if(modified && !database.empty())
    {
        sqlite3* dbhandle;
        if(0!=sqlite3_open(database.c_str(),&dbhandle)){
            cerr<<"Fail to open config database :"<<database<<endl;
            return;
        }
        
        //Write back new configs;
        while(!new_configs.empty()){
            string sql_new="INSERT INTO ";
            sql_new.append(config_table);
            sql_new.append(" (key,value) values ( \"");
            ConfigMap::iterator itr=*(new_configs.begin());
            sql_new.append(itr->first).append("\",\"").append(itr->second).append(");");
            
            sqlite3_stmt* stmt;
            sqlite3_prepare(dbhandle,sql_new.c_str(),sql_new.size(),&stmt,NULL);
            sqlite3_step(stmt);
        }
        new_configs.clear();

        //Write back modified configs;
        while(!modified_configs.empty()){
            ConfigMap::iterator itr=*(modified_configs.begin());
            string sql_modi="UPDATE OR ABORT ";
            sql_modi.append(config_table).append(" SET value=\"");
            sql_modi.append(itr->second).append("\" WHERE key=\"").append(itr->first).append("\";");
            sqlite3_stmt* stmt;
            sqlite3_prepare(dbhandle,sql_modi.c_str(),sql_modi.size(),&stmt,NULL);
            sqlite3_step(stmt);
        }
        modified_configs.clear();
        sqlite3_close(dbhandle);
    }
}

TFConfigurator::~TFConfigurator()
{
    if(modified)
        WriteBack();
}

#ifdef __TF_DEBUG__
void TFConfigurator::ShowAll()
{
    cout<<"Show all "<<configs.size()<<" elements"<<endl;
    for(ConfigMap::iterator itr=configs.begin();itr!=configs.end();itr++)
    {
        cout<<itr->first.c_str()<<":"<<itr->second.c_str()<<endl;
    }
}
#endif
